﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace IntoTheme.Controls
{
    /// <summary>
    /// 按照步骤 1a 或 1b 操作，然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
    ///
    /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
    /// 元素中:
    ///
    ///     xmlns:MyNamespace="clr-namespace:IntoTheme.Controls"
    ///
    ///
    /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
    /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
    /// 元素中:
    ///
    ///     xmlns:MyNamespace="clr-namespace:IntoTheme.Controls;assembly=IntoTheme.Controls"
    ///
    /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用，
    /// 并重新生成以避免编译错误:
    ///
    ///     在解决方案资源管理器中右击目标项目，然后依次单击
    ///     “添加引用”->“项目”->[浏览查找并选择此项目]
    ///
    ///
    /// 步骤 2)
    /// 继续操作并在 XAML 文件中使用控件。
    ///
    ///     <MyNamespace:DashBoard/>
    ///
    /// </summary>
    public class DashBoard : Control
    {
        static DashBoard()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DashBoard), new FrameworkPropertyMetadata(typeof(DashBoard)));
        }

        private void InitTick()
        {
            // 画大刻度
            for (int i = 0; i < 5; i++)
            {
                Line line = new Line();
                line.X1 = 0;
                line.Y1 = 0;
                line.X2 = 0;
                line.Y2 = 12;
                line.Stroke = Brushes.Green;
                line.StrokeThickness = 2;
                line.HorizontalAlignment = HorizontalAlignment.Center;
                line.RenderTransformOrigin = new Point(0, 0.95);
                line.RenderTransform = new RotateTransform() { Angle = -90 + i * 45 };
                bdGrid.Children.Add(line);
                DrawText();
            }

            // 画小刻度
            for (int i = 0; i < 4; i++)
            {
                var start = -90 + 45 * i + 9;
                for (int j = 0; j < 4; j++)
                {
                    Line line = new Line();
                    line.X1 = 0;
                    line.Y1 = 0;
                    line.X2 = 0;
                    line.Y2 = 6;
                    line.Stroke = Brushes.Green;
                    line.StrokeThickness = 1;
                    line.HorizontalAlignment = HorizontalAlignment.Center;
                    line.RenderTransformOrigin = new Point(0, 0.95);
                    line.RenderTransform = new RotateTransform() { Angle = start + j * 9 };
                    bdGrid.Children.Add(line);
                }
            }
        }

        List<Label> textLabels = new List<Label>();
        private void DrawText()
        {
            foreach (var item in textLabels)
            {
                bdGrid.Children.Remove(item);
            }
            textLabels.Clear();

            var per = MaxValue / 4;
            for (int i = 0; i < 5; i++)
            {
                Label lb = new Label();
                lb.Content = $"{MinValue + (per * i)}";
                lb.HorizontalAlignment = HorizontalAlignment.Center;
                lb.RenderTransformOrigin = new Point(0.5, 1);
                lb.RenderTransform = new RotateTransform() { Angle = -90 + i * 45 };
                lb.Margin = new Thickness(12);
                lb.Foreground = Brushes.Black;
                lb.FontSize = 12;
                textLabels.Add(lb);
                bdGrid.Children.Add(lb);
            }
        }

        RotateTransform rotateTransform;
        Grid bdGrid;
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            rotateTransform = GetTemplateChild("PointRotate") as RotateTransform;
            bdGrid = GetTemplateChild("bdGrid") as Grid;
            Refresh();
            InitTick();
        }

        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(DashBoard), new PropertyMetadata(0d, OnValueChanged));

        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as DashBoard)?.Refresh();

        public double MinValue
        {
            get { return (double)GetValue(MinValueProperty); }
            set { SetValue(MinValueProperty, value); }
        }
        public static readonly DependencyProperty MinValueProperty =
            DependencyProperty.Register("MinValue", typeof(double), typeof(DashBoard), new PropertyMetadata(0d, OnValueChanged));

        public double MaxValue
        {
            get { return (double)GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }

        public static readonly DependencyProperty MaxValueProperty =
            DependencyProperty.Register("MaxValue", typeof(double), typeof(DashBoard), new PropertyMetadata(0d, OnValueChanged));


        private void Refresh()
        {
            if (rotateTransform == null)
                return;
            InitTick();
            DoubleAnimation da = new DoubleAnimation();
            da.Duration = new Duration(TimeSpan.FromMilliseconds(350));
            da.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };

            if (Value > MaxValue)
            {
                rotateTransform.Angle = 90;
                da.To = 90;
            }
            else if (Value < MinValue)
            {
                rotateTransform.Angle = -90;
                da.To = -90;
            }
            else
            {
                var range = MaxValue - MinValue;
                var process = Value / range;
                var tAngle = process * 180 - 90;
                rotateTransform.Angle = tAngle;
                da.To = tAngle;
            }

            rotateTransform.BeginAnimation(RotateTransform.AngleProperty, da);
        }

    }
}
